package com.h819.core.utils.date;

import com.h819.core.utils.MyMathUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.LocalDate;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

/**
 * @Title: MyDateUtilsExtend.java
 * @Description: TODO(时间，日期工具类。和 MyDateUtils 类一起使用。主要参考 JodaTime 和
 *               apacha.commons.lang.DateUtils)
 * @author H819
 * @date 2010-3-4
 * @version V1.0
 */

// 参考
// http://joda-time.sourceforge.net/quickstart.html
// org.apache.commons.lang.DateUtils
// http://www.ibm.com/developerworks/cn/java/j-jodatime.html?ca=drs-cn-1214
public class MyDateUtilsExtend {

	static Logger log = Logger.getLogger(MyDateUtilsExtend.class);

	// ====== 正则表达式(为了字符串合并的时候不产生歧义，每个子字符串都用括号()括起来)=====
	/* 判断是否是正确的年份,必须以 19,20 开头，并且是四位 */
	public static String yearPatternReg = "((19|20)[0-9]{2})";
	/* 判断日期格式 yyyy-MM-dd */
	public static String datePatternReg = "((19|20)[0-9]{2}-(0[1-9]|1[012])-(0[1-9]|[12][0-9]|3[01]))";
	/* 判断时间格式 HH:mm:dd */
	public static String time24PatternReg = "((0[0-9]|1[0-9]|2[0-4]):(0[0-9]|[1-5][0-9]|60):(0[0-9]|[1-5][0-9]|60))";
	/* 判断日期格式 yyyy-MM-dd HH:mm:dd */
	public static String dateTime24PatternReg = datePatternReg + " "
			+ time24PatternReg;

	// ===== 字符串 =====
	// year
	public static String yearPattern = "yyyy";
	// date
	public static String datePattern = "yyyy-MM-dd";
	// 24 小时制
	public static String timePattern24 = "HH:mm:ss";
	// 12 小时制
	public static String timePattern12 = "hh:mm:ss";
	// 24 小时制
	public static String dateTime24Pattern = datePattern + " " + timePattern24;
	// 12 小时制
	public static String dateTime12Pattern = datePattern + " " + timePattern12;

	/**
	 * 构造函数
	 */
	public MyDateUtilsExtend() {
		// TODO Auto-generated constructor stub
	}

	/**
	 * 判断当前日期
	 * 
	 * @return
	 */
	public static DateTime getNow() {
		return new DateTime();
	}

	/**
	 * 得到给定的日期是星期几
	 * 
	 * @param date
	 * @return 星期几，为数字
	 */
	public static int getDayOfWeek(Date date) {
		return toDateTime(date).getDayOfWeek();
	}

	/**
	 * 得到给定的日期是是几号
	 * 
	 * @param date
	 * @return
	 */
	public static int getDayOfMonth(Date date) {
		return toDateTime(date).getDayOfMonth();
	}

	/**
	 * 得到给定的日期是一年中的第几天
	 * 
	 * @param date
	 * @return
	 */
	public static int getDayOfYear(Date date) {
		return toDateTime(date).getDayOfYear();
	}

	/**
	 *得到给定的日期是一年中的第几周
	 * 
	 * @param date
	 * @return
	 */
	public static int getWeekOfWeekyear(Date date) {
		return toDateTime(date).getWeekOfWeekyear();
	}

	/**
	 * 计算两个任意时间中间的间隔天数
	 * 
	 * @param startday
	 * @param endday
	 * @return
	 */
	public static int getDaysBetween(DateTime startday, DateTime endday) {
		return Days.daysBetween(startday, endday).getDays();

	}


	/**
	 * 秒->分钟,保留两位小数
	 * 
	 * @param second
	 *            输入的秒
	 * @return 分钟数,四舍五入,保留两位小数
	 */
	public static double secondToMinute(long second) {

		double v1 = new java.lang.Long(second).doubleValue();
		double v2 = 60.0;
		return MyMathUtils.div(v1, v2, 2);

	}

	/**
	 * 秒->小时,保留两位小数
	 * 
	 * @param second
	 *            输入的秒
	 * @return 小时,四舍五入,保留两位小数
	 */
	public static double secondToHour(long second) {
		double v1 = new java.lang.Long(second).doubleValue();
		double v2 = 3600.0;
		return MyMathUtils.div(v1, v2, 2);
	}

	/**
	 * 秒->小时,保留两位小数
	 * 
	 * @param second
	 *            输入的秒
	 * @return 小时,四舍五入,保留两位小数
	 */
	public static double secondToHour(double second) {
		// double v1 = new java.lang.Long(second).doubleValue();
		double v2 = 3600.0;
		return MyMathUtils.div(second, v2, 2);
	}



	/**
	 * 用字符串构造 DateTime，字符串要满足时间格式要求，使用的时候，要根据具体格式进行测试
	 * 
	 * @param dateStr
	 *            待判断的字符串
	 * @param patternStr
	 *            SimpleDateFormat 能够解析的时间格式，使用的时候，要根据具体格式进行测试
	 * @return
	 */
	public static DateTime toDateTime(String dateStr, String patternStr) {

		try {
			Date jdkDate = new SimpleDateFormat(patternStr).parse(dateStr);
			return toDateTime(jdkDate);
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * Jdk Date 转换为 DateTime
	 * 
	 * @param date
	 * @return
	 */
	public static DateTime toDateTime(Date date) {
		return new DateTime(date.getTime());
	}

	/**
	 * Jdk Calendar 转换为 DateTime
	 * 
	 * @param cal
	 * @return
	 */
	public static DateTime toDateTime(Calendar cal) {
		return new DateTime(cal);
	}
	
	/**
	 * 判断某年是否为闰年
	 * 
	 * @param yearStr
	 *            给定的四位年号
	 * @return
	 */
	public static boolean isLeapYear(String yearStr) {

		// 判断是否为四位年号
		if (!isDateStrByReg(yearStr, yearPatternReg))
			return false;
		try {
			Date jdkDate = new SimpleDateFormat(yearPattern).parse(yearStr);
			return toDateTime(jdkDate).year().isLeap();
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return false;
		}
	}

	/**
	 * 判断某年是否为闰年。用上面的方法代替，隐藏实现细节
	 * 
	 * @param yearNum
	 * @return
	 */
	/*
	 * public static boolean isLeapYear(int yearNum) { boolean isLeep = false;
	 * //判断是否为闰年，赋值给一标识符flag / if ((yearNum % 4 == 0) && (yearNum % 100 != 0)) {
	 * isLeep = true; } else if (yearNum % 400 == 0) { isLeep = true; } else {
	 * isLeep = false; } return isLeep; }
	 */

	/**
	 * 判断给定日期字符串格式是否满足正则表达式
	 * 
	 * @param dateStr
	 *            给的的日期字符串
	 * @param patternReg
	 *            该字符串必须为正则表达式
	 * @return
	 */
	public static boolean isDateStrByReg(String dateStr, String patternReg) {

		boolean foundMatch = false;
		try {
			Pattern regex = Pattern.compile(patternReg);
			Matcher regexMatcher = regex.matcher(dateStr);
			foundMatch = regexMatcher.matches();
		} catch (PatternSyntaxException ex) {
			// Syntax error in the regular expression
		}
		log.info("foundMatch :" + foundMatch);
		return foundMatch;
	}

	/**
	 * 补足不完整的两位的年号
	 * 
	 * @param year
	 *            给定的年代，缺少 19 或者 20
	 * @return 补充完整的四位年代号
	 */
	public static String fillYear2To4(String year) {
		String realYear = year.trim();
		// 年为非数字
		if (!StringUtils.isNumeric(realYear))
			return null;
		// log.info("year :" + year);
		if (realYear.length() == 2) {// 补足两位年代
			try {
				int yearCode = Integer.valueOf(realYear);
				// log.info("yearCode :" + yearCode);
				// === 00 - 30 默认为 20 开头
				if (0 < yearCode && yearCode < 10)// 如果年号为
					// 07,那么转换为整数的时候，会去掉
					// 0,故加上此句
					realYear = "200" + Integer.toString(yearCode);
				else if (10 <= yearCode && yearCode <= 30) // 判断到 2030 年足矣
					realYear = "20" + Integer.toString(yearCode);
				// === 30 - 99 默认为 19 开头
				else if (30 < yearCode && yearCode <= 99)
					realYear = "19" + Integer.toString(yearCode);
				else {
					// log.info("wrong year :" + yearCode);
					return null;
				}
			} catch (Exception ex) {// 年号错误
				ex.printStackTrace();
				return null;
			}
		} else if (realYear.length() == 4) {
			if (!realYear.matches(yearPatternReg)) {// 不是正确的四位年号;
				// log.info(Year + " : is not right year");
				return null;
			}
		} else {
			// log.info(Year + " : is not right year");
			return null;
		}
		return realYear;
	}

	/**
	 * 临时日期变量计算，参见 http://www.ibm.com/developerworks/cn/java/j-jodatime.html?ca=drs-cn-1214
	 */
	public static void modifyDateExample() {

		/*
		 * 应用程序所需处理的日期问题并不全部都与时间上的某个完整时刻有关，因此您可以处理一个局部时刻。例如，有时您比较关心年/月/日，或者一天中的时间
		 * ，甚至是一周中的某天 。Joda 设计者使用 ReadablePartial
		 * 接口捕捉这种表示局部时间的概念，这是一个不可变的局部时间片段。用于处理这种时间片段的两个有用类分别为 LocalDate 和
		 * LocalTime：
		 * LocalDate：该类封装了一个年/月/日的组合。当地理位置（即时区）变得不重要时，使用它存储日期将非常方便。例如，
		 * 某个特定对象的出生日期 可能为 1999 年 4 月 16
		 * 日，但是从技术角度来看，在保存所有业务值的同时不会了解有关此日期的任何其他信息（比如这是一周中的星期几，或者这个人出生地所在的时区
		 * ）。在这种情况下，应当使用 LocalDate。 样例应用程序使用 SystemClock 来获取被初始化为系统时间的 LocalDate
		 * 的实例： LocalDate localDate = SystemFactory.getClock().getLocalDate();
		 * 
		 * 也可以通过显式地提供所含的每个字段的值来创建 LocalDate： LocalDate localDate = new
		 * LocalDate(2009, 9, 6);// September 6, 2009
		 * 
		 * LocalDate 替代了在早期 Joda 版本中使用的 YearMonthDay。
		 * LocalTime：这个类封装一天中的某个时间，当地理位置不重要的情况下，可以使用这个类来只存储一天当中的某个时间。例如，晚上 11:52
		 * 可能是一天当中的一个重要时刻（比如，一个 cron
		 * 任务将启动，它将备份文件系统的某个部分），但是这个时间并没有特定于某一天，因此我不需要了解有关这一时刻的其他信息。 样例应用程序使用
		 * SystemClock 获取被初始化为系统时间的 LocalTime 的一个实例： LocalTime localTime =
		 * SystemFactory.getClock().getLocalTime();
		 * 
		 * 也可以通过显式地提供所含的每个字段的值来创建 LocalTime： LocalTime localTime = new
		 * LocalTime(13, 30, 26, 0);// 1:30:26PM
		 */

		//修改日期
		LocalDate loc = new LocalDate();//当前日期
		System.out.println(loc);
		System.out
				.println(loc.year().setCopy(2009).weekOfWeekyear().setCopy(4));
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

		// MyDateUtilsExtend.

		// System.out.println(MyDateUtilsExtend.isLeapYear(1999));
		// System.out.println(MyDateUtilsExtend.isLeapYear("200"));

		// System.out.println(MyDateUtilsExtend.isDateStrByReg(
		// "2001-12-31 12:15:30", MyDateUtilsExtend.dateTime24PatternReg));
		//
		// System.out.println(MyDateUtilsExtend.toDateTime("2001-03-31",
		// "yyyy-MM-dd").toString());

		// System.out.println(new DateTime("200122"));

		MyDateUtilsExtend.modifyDateExample();

		// System.out.println(MyDateUtilsExtend.getNow());

		try {
			String s = new SimpleDateFormat("hh:mm:ss").parse("11:30:30")
					.toString();
			// System.out.println(s);
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

}
